package com.woniuxy.gateway.filter;

import com.fasterxml.jackson.databind.ObjectMapper;

import com.woniuxy.commons.utils.JwtUtil;
import com.woniuxy.commons.utils.ResponseResult;
import com.woniuxy.commons.utils.ResultStatus;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

@Component
public class AuthFilter implements GlobalFilter, Ordered {
    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    //执行过滤方法，与zuul的run方法作用一致
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取request  此request非彼request
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        //获取uri
        String uri = request.getURI().getPath();

        //判断uri是否需要认证才能访问
        if (validate(uri)){
            //不需要认证，放行
            return chain.filter(exchange);
        }

        //执行到此处，说明上面的if不成立，表示需要认证
        //获取头信息

        String token = null;
        List<String> auths = request.getHeaders().get("authentication");
        if (auths != null){
            token = auths.get(0);
        }
        String refresh = null;
        List<String> refreshList = request.getHeaders().get("refresh");
        //["null"]
        if (refreshList != null){
            refresh = refreshList.get(0);
        }

        //判断token、refresh是否为null

            if (token.equals("null") || refresh.equals("null")) {

                //没携带token、refresh 说明没登录，直接结束，返回让登录的结果
                return result(response);
            }


        //执行到此处说明token、refresh都不为空，只能说明携带了，还需要对它们进行校验
        //校验refresh：判断redis中是否有这个key，没有表示refresh伪造或者过期
        //
        System.out.println(redisTemplate.opsForValue().get("username"));
        if (!redisTemplate.hasKey(refresh)){
            //不含refresh
            return result(response);
        }
        System.out.println("校验token");
        //校验token
        switch (JwtUtil.verify(token)){
            case TOKEN_BAD:
                return result(response);
            case TOKEN_EXPIRE: {
                System.out.println("生成token");
                //重新生成token，并返回给浏览器
                token = JwtUtil.generateToken(JwtUtil.getUname(token));
                //将token设置到响应头
                response.getHeaders().add("authentication", token);
                //暴露头
                response.getHeaders().add("Access-Control-Expose-Headers", "authentication");

                //更新redis中的token

                break;
            }
        }

        //继续向下执行
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }

    private Mono<Void> result(ServerHttpResponse response){

        ResponseResult responseResult = new ResponseResult();
        responseResult.setMessage("请登录");
        responseResult.setCode(500);
        responseResult.setStatus(ResultStatus.NO_LOGIN);

//        需要蒋返回的对象转成byte的数组
        byte[] data = null;
        try {
            data = new ObjectMapper().writeValueAsString(responseResult).getBytes(StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }

        DataBuffer dataBuffer = response.bufferFactory().wrap(data);

        response.getHeaders().add("Content-Type",
                "application/json;charset=utf-8");


        return response.writeWith(Mono.just(dataBuffer));

    }

    //校验uri是否需要进行认证才能访问
    private boolean validate(String uri){
        //    /auth/login   正则
        List<String> anon = Arrays.asList(
                "/auth",
                "/file",
                "/myorders"
//                ,"/staff"
//                ,"/zqqtestnacos"
        );
        //lambda表达式   for(String str : anon)
        for (String str: anon){
            if (uri.startsWith(str)){
                return true;
            }
        }
        return false;
    }
}
